/**
 * Author:yuiop
 * Date:2022/9/22 14:29
 */
package com.devops.admin.config;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.devops.admin.config.bean.AliyunAccountProperties;
import com.devops.admin.util.EnvironmentUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.AbstractEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.lang.NonNull;

import java.util.Set;

@Slf4j
public class AliyunAccountMultiDataSourceRegistrar implements EnvironmentAware, ImportBeanDefinitionRegistrar {
    private Environment environment;

    @Override
    public void setEnvironment(@NonNull Environment environment) {
        this.environment = environment;
    }

    @Override
    public void registerBeanDefinitions(@NonNull AnnotationMetadata annotationMetadata,
                                        @NonNull BeanDefinitionRegistry registry) {
        Set<String> names = EnvironmentUtil.loadAliyunAccountDataSourceName((AbstractEnvironment)environment);
        if (names.size() <= 0) {
            log.error("no multi aliyun account datasource config");
            return;
        }
        log.info("register multi aliyun account datasource: {}",names);
        for (String name:names) {
            registerAcsClientBeanDefinition(name,AcsClientFactoryBean.class,registry);
        }
    }

    /**
     * 注册 RedisTemplate BeanDefinition
     */
    protected final void registerAcsClientBeanDefinition(String alias, Class<?> type, BeanDefinitionRegistry registry) {
        // BeanDefinition构建器
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(type);
        // 设置通过名称注入
        builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_NAME);
        builder.addConstructorArgValue(null);
        // 设置数据源的名称(即设置bean的dataSourceName属性的值)
        builder.addPropertyValue(AliyunAccountDataSourceContext.FIELD_DATASOURCE_NAME, alias);

        // 通过构建器获取bean的定义信息
        BeanDefinition beanDefinition = builder.getBeanDefinition();
        // 设置主要的注入的对象
        beanDefinition.setPrimary(false);

        String beanName = alias + "AcsClient";
        // 设置该bean的名称（数据源名称 + AcsClient）和别名（数据源名称 + -client）
        BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, beanName, new String[]{alias + "-acs-client"});
        // 注册bean定义信息
        BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
    }

    protected class AcsClientFactoryBean extends AliyunAccountDataSourceContext implements FactoryBean<Object> {
        /**
         * 返回要创建的bean对象
         */
        @Override
        public Object getObject() throws Exception {
            AliyunAccountProperties aliyunAccountProperties = getAliyunAccountProperties();
            String regionId = "cn-hangzhou";
            IClientProfile profile = DefaultProfile.getProfile(regionId, aliyunAccountProperties.getAccessKeyId(), aliyunAccountProperties.getAccessKeySecret());
            // 若报Can not find endpoint to access异常，请添加以下此行代码
            // DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", "Alidns", "alidns.aliyuncs.com");
            return new DefaultAcsClient(profile);
        }

        /**
         * 返回要创建的bean的类型
         */
        @Override
        public Class<?> getObjectType() {
            return IAcsClient.class;
        }
    }

}
